home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Plug-In Power Pack for Netscape Communicator
/
Plug-In Power Pack for Netscape Communicator.iso
/
plugins
/
dataviews
/
include
/
fdsevalfuns.h
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-08
|
29KB
|
956 lines
#ifndef lint
static char SccsId_FDSevalfuns[] = "@(#)FDSevalfuns.h V1.32 3/16/95";
#endif
/*
| file name - FDSevalfuns.h
|===================================================================
|
| copyright (c) 1989,1992 V.I. Corporation
|
| FDSevalfuns - Function definitions for FDSeval
|
| Alan C Morse 31 may 89
| Alan C Morse 30 Dec 92 Added more functions: the
| ANSI C functions we don't
| yet support. atan2, ceil, exp,
| fabs, floor, fmod, log, log10
| Bit functions: bitand, bitor, bitxor
| bitnot, bitget, bitset, bitclear;
| Stat funs: runmax, runmedian,
| runmean, runmin, and runsdev
| Alan C Morse 13 Jan 92 Added math funs pow and exp10
|
|===================================================================
|
| Procedure description/function:
| Module containing function table and function definitions
| for FDSeval expression evaluator.
|
| This is meant to be included in the eval.c module of FDSeval.
|
| To add new functions:
| 1) Write the function, type LOCAL double. If the function
| is a system function, you don't need a local function
| usually, but if you do, use the same name but with the
| first letter capitalized.
| 2) Increment the NUMFCNS define
| 3) Add it to FcnTable at the end of this file, giving
| 3 fields: a) the name of the function as it would
| be typed in the expression; b) the name of the
| function in this module; and c) the number
| of arguments it expects. Putting things in
| alphabetical order and adding a comment field
| would be nice, too, but it is not required.
|
|===================================================================
*/
#include "std.h"
#include "vi/VUmiscfuns.h"
/*--------------------------------------------------------------*/
/* Functions for use in expressions */
/*--------------------------------------------------------------*/
/* Simple functions; front ends for system function */
LOCAL double Abs( a ) double a; { return DV_VIABS(a); }
/* -------------------------------------------------------
Exp10
exp10 is derived from the exp using the rule that
(a**b)**c : (a raised to b) raised to c
is the same as a**(b*c) : a raised to b*c
Hence:
10**a = (e ** log(10) ) ** a = e ** ( log10 * a )
*/
LOCAL double NaturalLogOf10 = 0;
LOCAL double Exp10( a )
double a;
{
if( NaturalLogOf10 == 0 )
NaturalLogOf10 = log(10.0);
return exp( a * NaturalLogOf10 );
}
LOCAL double Fmod( a, b )
double a,b;
{
if( b != 0 )
return fmod(a,b);
else
return 0;
}
LOCAL double Log( a )
double a;
{
if( a > 0 )
return log(a);
else
return 0;
}
LOCAL double Log10( a )
double a;
{
if( a > 0 )
return log10(a);
else
return 0;
}
LOCAL double Min( a, b ) double a,b; { return S_MIN(a,b); }
LOCAL double Max( a, b ) double a,b; { return S_MAX(a,b); }
LOCAL double Pow( a, b )
double a,b;
{
if( a > 0 )
return pow(a, b);
else
return 0;
}
/*==============================================================
| BIT operations
================================================================*/
typedef unsigned long INT32BITS;
/*--------------------------------------------------------------
| bitand
| Returns bitwise AND of int32 versions of a and b.
*/
LOCAL double bitand( a, b )
double a,b;
{
return (double)( (INT32BITS)a & (INT32BITS)b );
}
/*--------------------------------------------------------------
| bitclear
| CLEARs b-th bit of int32 version of a; 0 is least significant bit.
| Returns a after the operation.
*/
LOCAL double bitclear( a, b )
double a,b;
{
INT32BITS ia, ib;
ib = (INT32BITS)b;
ia = (INT32BITS)a;
/* Next line causes warning "unsigned value >= 0 is always 1".
* But keep it anyway in case definition of INT32BITS ever
* changes to be signed.
*/
if( ib >= 0 && ib <= 31 )
ia = ~(1<<ib) & ia;
return (double)ia;
}
/*--------------------------------------------------------------
| bitget
| Returns the b-th bit of int32 version of a; 0 is least significant bit.
*/
LOCAL double bitget( a, b )
double a,b;
{
INT32BITS ia, ib;
ib = (INT32BITS)b;
ia = (INT32BITS)a;
/* Next line causes warning "unsigned value >= 0 is always 1".
* But keep it anyway in case definition of INT32BITS ever
* changes to be signed.
*/
if( ib >= 0 && ib <= 31 )
if( ia & (1<<ib) )
return (double)1;
else
return (double)0;
else
return (double)0;
}
/*--------------------------------------------------------------
| bitnot
| Returns bitwise NOT of int32 version of a.
*/
LOCAL double bitnot( a )
double a;
{
return (double)( ~(INT32BITS)a );
}
/*--------------------------------------------------------------
| bitor
| Returns bitwise OR of int32 versions of a and b.
*/
LOCAL double bitor( a, b )
double a,b;
{
return (double)( (INT32BITS)a | (INT32BITS)b );
}
/*--------------------------------------------------------------
| bitset
| SETs b-th bit of int32 version of a; 0 is least significant bit.
| Returns a after the operation.
*/
LOCAL double bitset( a, b )
double a,b;
{
INT32BITS ia, ib;
ib = (INT32BITS)b;
ia = (INT32BITS)a;
/* Next line causes warning "unsigned value >= 0 is always 1".
* But keep it anyway in case definition of INT32BITS ever
* changes to be signed.
*/
if( ib >= 0 && ib <= 31 )
ia = (1<<ib) | ia;
return (double)ia;
}
/*--------------------------------------------------------------
| bitxor
| Returns bitwise XOR of int32 versions of a and b.
*/
LOCAL double bitxor( a, b )
double a,b;
{
return (double)( (INT32BITS)a ^ (INT32BITS)b );
}
/*--------------------------------------------------------------
|
| mk_normrand
| Makes a bunch of normally distributed random numbers.
| It fills a caller-supplied table with the numbers.
| Based on the Box-Muller transformation on p.453 of
| NUMERICAL METHODS. The mean of the distribution is zero,
| and the standard deviation is one. Called by gnoise.
*/
LOCAL DV_BOOL L_randseeded = NO;
#ifndef PI
#define PI 3.14159265358979323846264338327950
#endif
LOCAL VOID mk_normrand( table, size )
FAST double *table;
int size;
{
int i;
double radius, angle;
double r1,r2,n1,n2;
VUsrand(4321);
L_randseeded = YES;
for( i=size/2; i>0; i-- )
{
r1 = VUfrand();
r2 = VUfrand();
if( r1 > 0 && r1 <= 1 )
radius = sqrt( -2.0 * log( r1 ) );
else
/* r1 is not valid, kludge up an alternate value */
/* If this happens, the distribution is no longer gaussian */
radius = DV_VIABS(r1);
angle = 2 * PI * r2;
n1 = radius * cos( angle );
n2 = radius * sin( angle );
/* table entry = mean + standard_deviation * n[12] */
*table++ = n1;
*table++ = n2;
}
}
/*---------------------------------------------------------------- */
/* gnoise: Gaussian noise generator, w/ mean of 0 and stdev of 1 */
#define RAN_TABLE_SIZE 1024 /* Must be a power of two */
LOCAL double *RanNumTable = 0;
LOCAL double gnoise()
{
if( RanNumTable == NULL )
{
RanNumTable = (double*)S_ALLOC( RAN_TABLE_SIZE * sizeof(double) );
mk_normrand( RanNumTable, RAN_TABLE_SIZE ); /* Fill it in */
}
return RanNumTable[ VUrand() & (RAN_TABLE_SIZE-1) ];
}
/*----------------------------------------------------------------
| Hypot: return sqrt( a*a + b*b );
*/
LOCAL double Hypot( a, b )
double a, b;
{
return sqrt( a*a + b*b );
}
/*---------------------------------------------------------------- */
/* wnoise: white noise in range [0,1] */
LOCAL double wnoise()
{
if (!L_randseeded)
{
VUsrand(4321);
L_randseeded = YES;
}
return VUfrand();
}
/*---------------------------------------------------------------- */
/* saw: Sawtooth wave generator.... /|/|/|/| */
/* with data in range 0 to 1, with specified period */
LOCAL double saw( iteration, period )
double iteration, period;
{
double p;
/* Bring iteration into the range [0,period] */
p = iteration - ((int)(iteration/period)) * period;
return p / period;
}
/*---------------------------------------------------------------- */
/* rsaw: Reverse sawtooth wave generator.... |\|\|\|\ */
/* with data in range 0 to 1, with specified period */
LOCAL double rsaw( iteration, period )
double iteration, period;
{
double p;
/* Bring iteration into the range [0,period] */
p = iteration - ((int)(iteration/period)) * period;
p = period - p;
return p / period;
}
/*---------------------------------------------------------------- */
/* tri: Triangle wave generator.... /\/\/\/\ */
/* with data in range 0 to 1, with specified period */
LOCAL double tri( iteration, period )
double iteration, period;
{
double p;
/* Bring iteration into the range [0,period] */
p = iteration - ((int)(iteration/period)) * period;
if( p > period/2.0 )
p = period - p;
return 2 * p / period;
}
/*---------------------------------------------------------------- */
/* time: Unix time function. Returns the number of seconds */
/* since Jan 1, 1970, 00:00.00. */
LOCAL double Time()
{
return (double)time( 0 );
}
/*---------------------------------------------------------------- */
/* delay: Data stream a delayed by b time units. */
LOCAL VOID FreeDelayParams( p )
RING_BUFFER *p;
{
if( p )
DESTROY_RING_BUFFER( p );
}
LOCAL double delay( a, delay_amount )
double a,delay_amount;
{
double *d;
int i, t;
double result;
RING_BUFFER *ringbuf; /* Local variable for ring buffer, since some
| compilers choke on CREATE_RING_BUFFER( GlobalEnv.CurrentNode->params... */
ringbuf = (RING_BUFFER*)GlobalEnv.CurrentNode->params;
if( ringbuf == NULL )
{ /* First call, create the ring buffer */
t = S_MAX( 1, (int)(delay_amount + 0.5) );
CREATE_RING_BUFFER( ringbuf, t, (LONG)sizeof(double) );
GlobalEnv.CurrentNode->params = (ADDRESS)ringbuf;
GlobalEnv.CurrentNode->FreeParams = FreeDelayParams;
/* Prime the ring buffer with zeros */
for( i=0; i<t; i++ )
{
d = (double*)RING_BUFFER_ENTRY( ringbuf, i );
*d = (double)0;
}
}
/* Get the oldest value */
d = (double*)RING_BUFFER_ENTRY( ringbuf, 0 );
result = *d;
*d = a; /* Replace oldest value with newest value. */
INCREMENT_RING_BUFFER( ringbuf, 1 );
return result;
}
/*================================================================*/
/* STATISTICS functions */
/* over a time window */
/* Prefixed by "run" */
/*================================================================*/
/*----------------------------------------------------------------*/
/* Data buffer for time-windowed (running) functions. */
/* The "RunningValue" datum is interpreted differently */
/* depending on the function being performed. */
typedef struct
{
int iteration, width;
double RunningValue; /* Used for storing incremental intermediate data */
double RunningValue2; /* Used for storing incremental intermediate data */
RING_BUFFER *values; /* Buffered data values. There are width of them. */
} RUNDATA_PARAMS;
/* Allocate a RUNDATA_PARAMS structure */
LOCAL RUNDATA_PARAMS *AllocRunParams( width )
double width;
{
int iwidth;
FAST RUNDATA_PARAMS *p;
iwidth = S_MAX( 0, (int)(width+0.5) );
p = (RUNDATA_PARAMS*)S_ALLOC( sizeof(RUNDATA_PARAMS) );
p->iteration = 0;
p->width = S_MAX( 0, (int)(width+0.5) );
p->RunningValue = 0;
p->RunningValue2 = 0;
if( p->width )
{ CREATE_RING_BUFFER( p->values, p->width, (LONG)sizeof(double) ); }
else
p->values = (RING_BUFFER*)0;
return p;
}
/* Free a RUNDATA_PARAMS structure */
LOCAL VOID FreeRunParams( p )
RUNDATA_PARAMS *p;
{
if( p )
{
if( p->values ) DESTROY_RING_BUFFER( p->values );
S_FREE( (ADDRESS) p );
}
}
/*---------------------------------------------------------------- */
/* runmax: The running max of a, over an interval of width points */
/* width should be a constant, since it is only examined the */
/* first time through. If width is zero, the running max */
/* is over an infinitely wide period */
LOCAL double runmax( a, width )
double a,width;
{
RUNDATA_PARAMS *p;
double *d;
DV_BOOL RecalcMax;
int i;
if( GlobalEnv.CurrentNode->params == NULL )
{
GlobalEnv.CurrentNode->params = (ADDRESS)AllocRunParams( width );
GlobalEnv.CurrentNode->FreeParams = FreeRunParams;
p = (RUNDATA_PARAMS*)GlobalEnv.CurrentNode->params;
p->RunningValue = a; /* Initialize the maximum */
}
else
{
p = (RUNDATA_PARAMS*)GlobalEnv.CurrentNode->params;
if( a > p->RunningValue )
p->RunningValue = a;
}
p->iteration++;
if( p->width )
{
d = (double*)RING_BUFFER_ENTRY( p->values, 0 ); /* Get oldest value */
/* If we are about to delete the current max we will need to recalc. */
if( *d >= p->RunningValue )
RecalcMax = YES;
else
RecalcMax = NO;
*d = a; /* Replace oldest value with newest value. */
INCREMENT_RING_BUFFER( p->values, 1 ); /* Move past new value to next oldest */
if( RecalcMax )
{
d = (double*)p->values->buffer;
p->RunningValue = *d++;
for( i = p->width-1; i>0; i--, d++ )
if( *d > p->RunningValue )
p->RunningValue = *d;
}
}
return p->RunningValue;
}
/*---------------------------------------------------------------- */
/* runmin: The running min of a, over an interval of width points */
/* width should be a constant, since it is only examined the */
/* first time through. If width is zero, the running min */
/* is over an infinitely wide period */
LOCAL double runmin( a, width )
double a,width;
{
RUNDATA_PARAMS *p;
double *d;
DV_BOOL RecalcMin;
int i;
if( GlobalEnv.CurrentNode->params == NULL )
{
GlobalEnv.CurrentNode->params = (ADDRESS)AllocRunParams( width );
GlobalEnv.CurrentNode->FreeParams = FreeRunParams;
p = (RUNDATA_PARAMS*)GlobalEnv.CurrentNode->params;
p->RunningValue = a; /* Initialize the minimum */
}
else
{
p = (RUNDATA_PARAMS*)GlobalEnv.CurrentNode->params;
if( a < p->RunningValue )
p->RunningValue = a;
}
p->iteration++;
if( p->width )
{
d = (double*)RING_BUFFER_ENTRY( p->values, 0 ); /* Get oldest value */
/* If we are about to delete the current min we will need to recalc. */
if( p->iteration > 1 && *d <= p->RunningValue )
RecalcMin = YES;
else
RecalcMin = NO;
*d = a; /* Replace oldest value with newest value. */
INCREMENT_RING_BUFFER( p->values, 1 ); /* Move past new value to next oldest */
if( RecalcMin )
{
d = (double*)p->values->buffer;
p->RunningValue = *d++;
for( i = S_MIN(p->width-1,p->iteration-1); i>0; i--, d++ )
if( *d < p->RunningValue )
p->RunningValue = *d;
}
}
return p->RunningValue;
}
/*---------------------------------------------------------------- */
/* runmean: The running mean of a, over an interval of width points */
/* width should be a constant, since it is only examined the */
/* first time through. If width is zero, the running mean */
/* is over an infinitely wide period */
LOCAL double runmean( a, width )
double a,width;
{
RUNDATA_PARAMS *p;
double *d;
double result;
if( GlobalEnv.CurrentNode->params == NULL )
{
GlobalEnv.CurrentNode->params = (ADDRESS)AllocRunParams( width );
GlobalEnv.CurrentNode->FreeParams = FreeRunParams;
}
p = (RUNDATA_PARAMS*)GlobalEnv.CurrentNode->params;
p->iteration++;
p->RunningValue += a;
if( p->width )
{
d = (double*)RING_BUFFER_ENTRY( p->values, 0 ); /* Get oldest value */
if( p->iteration > p->width )
{ p->RunningValue -= *d; result = p->RunningValue / (double)p->width; }
else
result = p->RunningValue / (double)p->iteration;
*d = a; /* Replace oldest value with newest value. */
INCREMENT_RING_BUFFER( p->values, 1 ); /* Move past new value to next oldest */
}
else
result = p->RunningValue / (double)p->iteration;
return result;
}
/*---------------------------------------------------------------- */
/* runmedian: The running median of a, over an interval of width points */
/* width should be a constant, since it is only examined the */
/* first time through. Unlike the mean, if width is zero, */
/* the running median can't be calculated over an infinite */
/* because the median calculation needs all the data to be saved, */
/* which would be too expensive. */
/* Iterative algorithm for finding the median of a data set without sorting */
/* If you pass in a reasonable first guess than the algorithm converges faster*/
/* This algorighm comes from Numerical Recipes In C, page 477-479. */
/* The median function needs DBL_MAX and DBL_MIN which are supposed to */
/* be in float.h. The sun doesn't have this include file in SunOS, but */
/* it does have values.h, which has MAXDOUBLE and MINDOUBLE */
#ifndef DBL_MAX
# ifdef SUNOS
# include <values.h>
# define DBL_MAX MAXDOUBLE
# define DBL_MIN MINDOUBLE
# else
# ifdef MASSCOMP
# include <values.h>
# define DBL_MAX MAXDOUBLE
# define DBL_MIN MINDOUBLE
# else
# include <float.h>
# endif
#endif
#endif
/* Amplification factors used in median calculation */
#define MEDIAN_AFAC 1.5
#define MEDIAN_AMP 1.5
LOCAL double median(x, n, FirstGuess)
double *x; /* Array of data values to find median */
int n; /* Size of array of data */
double *FirstGuess; /* First guess of median value;
if NULL make a guess in the routine. */
{
int NumAbove, /* Number of points above the current guess */
NumBelow, /* Number of points below the current guess */
i;
double xmed; /* Median */
double Guess, /* Current Guess at the median */
NextGuess, /* Next Guess at the median (temporary variable) */
GuessUpperBound, /* Upper bound on the median. */
GuessLowerBound, /* Lower bound on the median. */
AboveGuess, /* Value above guess and closest to it in the data set. */
BelowGuess, /* Value below guess and closest to it in the data set. */
Error; /* Difference between guess and calculated median. */
FAST double *datum;
double temp, sumx, sum, eps;
/* Make a guess at the median */
if( FirstGuess )
Guess = *FirstGuess;
else
Guess = 0.5 * (x[0] + x[n-1]);
eps = fabs(x[n-1] - x[0]);
/* First guess at characteristinc spacing of the data points near the median */
GuessLowerBound = -DBL_MAX;
GuessUpperBound = DBL_MAX;
FOREVER
{ /* Start a pass through the data */
sum = sumx = 0.0;
NumAbove = NumBelow = 0;
BelowGuess = -DBL_MAX;
AboveGuess = DBL_MAX;
/* For each data point */
for( datum = x, i = n; i > 0; datum++, i-- )
{
if (*datum != Guess)
{
if (*datum > Guess)
{
++NumAbove;
if (*datum < AboveGuess)
AboveGuess = *datum;
}
else if (*datum < Guess)
{
++NumBelow;
if (*datum > BelowGuess)
BelowGuess = *datum;
}
sum += temp = 1.0 / (eps + fabs(*datum - Guess));
sumx += *datum * temp;
}
}
Error = (sumx / sum) - Guess;
if (NumAbove - NumBelow >= 2)
{
GuessLowerBound = Guess;
NextGuess = Error < 0.0 ? AboveGuess : AboveGuess + Error * MEDIAN_AMP;
if (NextGuess > GuessUpperBound)
NextGuess = 0.5 * (Guess + GuessUpperBound);
eps = MEDIAN_AFAC * fabs(NextGuess - Guess);
Guess = NextGuess;
}
else if (NumBelow - NumAbove >= 2)
{
GuessUpperBound = Guess;
NextGuess = Error > 0.0 ? BelowGuess : BelowGuess + Error * MEDIAN_AMP;
if (NextGuess < GuessLowerBound)
NextGuess = 0.5 * (Guess + GuessLowerBound);
eps = MEDIAN_AFAC * fabs(NextGuess - Guess);
Guess = NextGuess;
}
else
{ /* Got the median */
if (n % 2 == 0)
{ /* For even n, median is always an average. */
if( NumAbove == NumBelow )
xmed = AboveGuess + BelowGuess;
else if (NumAbove > NumBelow )
xmed = Guess + AboveGuess;
else
xmed = BelowGuess + Guess;
xmed *= 0.5;
}
else
{ /* For odd n, median is always one point. */
if( NumAbove == NumBelow )
xmed = Guess;
else if( NumAbove > NumBelow )
xmed = AboveGuess;
else
xmed = BelowGuess;
}
return xmed;
}
}
}
/*----------------------------------------------------------*/
LOCAL double runmedian( a, width )
double a,width;
{
RUNDATA_PARAMS *p;
double *d;
if( GlobalEnv.CurrentNode->params == NULL )
{
if( width <= 0 ) width = 100;
GlobalEnv.CurrentNode->params = (ADDRESS)AllocRunParams( width );
GlobalEnv.CurrentNode->FreeParams = FreeRunParams;
}
p = (RUNDATA_PARAMS*)GlobalEnv.CurrentNode->params;
p->iteration++;
if( p->iteration <= p->width )
{
/* Add the new value to the data buffer at next empty slot. */
d = (double*)RING_BUFFER_ENTRY( p->values, p->iteration-1 );
*d = a;
/* Recalculate the median */
p->RunningValue = median( (double*)p->values->buffer,
p->iteration, &p->RunningValue );
}
else
{
/* Replace the oldest value with the current value */
d = (double*)RING_BUFFER_ENTRY( p->values, 0 ); /* Get oldest value */
*d = a;
/* Recalculate the median */
p->RunningValue = median( (double*)p->values->buffer,
p->width, &p->RunningValue );
/* Increment the ring buffer to move past new value to next oldest */
INCREMENT_RING_BUFFER( p->values, 1 );
}
return p->RunningValue;
}
/*---------------------------------------------------------------- */
/* runsdev: The running standard deviation of a, over an interval */
/* of width points. Width should be a constant, since it is only */
/* examined the first time through. If width is zero, the running */
/* standard deviation is over an infinitely wide period */
/* The equation that is used is
sqrt( ( sum of squares(a) - square of sum(a) / n ) / ( n - 1 ) )
This algorithm is not computationally optimal (according to,
Numerical Methods in C, pg 475), but it is suitable for incremental
(one-pass) calculation.
*/
LOCAL double runsdev( a, width )
double a,width;
{
RUNDATA_PARAMS *p;
double *d;
double result, num;
if( GlobalEnv.CurrentNode->params == NULL )
{
GlobalEnv.CurrentNode->params = (ADDRESS)AllocRunParams( width );
GlobalEnv.CurrentNode->FreeParams = FreeRunParams;
}
p = (RUNDATA_PARAMS*)GlobalEnv.CurrentNode->params;
p->iteration++;
p->RunningValue += a; /* Running sum */
p->RunningValue2 += a * a; /* Running sum of squares. */
if( p->width )
{
d = (double*)RING_BUFFER_ENTRY( p->values, 0 ); /* Get oldest value */
if( p->iteration > p->width )
{
p->RunningValue -= *d;
p->RunningValue2 -= ((*d) * (*d));
num = p->width;
}
else
num = p->iteration;
*d = a; /* Replace oldest value with newest value. */
INCREMENT_RING_BUFFER( p->values, 1 ); /* Move past new value to next oldest */
}
else
num = p->iteration;
if( num > 1 )
result = sqrt( ( p->RunningValue2 -
p->RunningValue * p->RunningValue / num ) / ( num - 1 ) );
else
result = 0;
return result;
}
/*---------------------------------------------------------------- */
/* delta: The change per unit time in a */
/* averaged over the last time_span time units */
/* NOTE: Use mean's data structure for storing parameters */
#define MAX_TIME_SPAN 2048
typedef struct
{
int iteration, width;
double FirstValue;
RING_BUFFER *values;
} DELTA_PARAMS;
LOCAL VOID FreeDeltaParams( p )
DELTA_PARAMS *p;
{
if( p )
{
if( p->values ) DESTROY_RING_BUFFER( p->values );
S_FREE( (ADDRESS) p );
}
}
LOCAL double delta( a, time_span )
double a, time_span;
{
DELTA_PARAMS *p;
double *d;
double result;
p = (DELTA_PARAMS*)GlobalEnv.CurrentNode->params;
if( GlobalEnv.CurrentNode->params == NULL )
{
GlobalEnv.CurrentNode->params = S_ALLOC( sizeof(DELTA_PARAMS) );
p = (DELTA_PARAMS*)GlobalEnv.CurrentNode->params;
p->iteration = 0;
p->width = S_MIN( MAX_TIME_SPAN, S_MAX( 1, (int)(time_span+0.5) ) );
p->FirstValue = a;
if( p->width )
{ CREATE_RING_BUFFER( p->values, p->width, (LONG)sizeof(double) ); }
GlobalEnv.CurrentNode->FreeParams = FreeDeltaParams;
}
p->iteration++;
d = (double*)RING_BUFFER_ENTRY( p->values, 0 ); /* Get oldest value */
if( p->iteration > p->width )
result = (a - *d) / (double)p->width;
else
/* Haven't run enough iterations yet */
/* Assume oldest value is is the same as the first value */
result = (a - p->FirstValue) / (double)p->iteration;
*d = a; /* Replace oldest value with newest value. */
/* Move past new value to next oldest */
INCREMENT_RING_BUFFER( p->values, 1 );
return result;
}
/*--------------------------------------------------------------*/
/* FUNCTION TABLE */
/*--------------------------------------------------------------*/
/* The typedef for FUN_DESC is in FDSeval.c */
#define NUMFCNS 45
LOCAL FUN_DESC FcnTable[NUMFCNS] =
{ /* Note for comments, arguments are (a,b,c...) */
"abs", Abs, 1, /* absolute value of a */
"acos", acos, 1, /* arc cosine of a */
"asin", asin, 1, /* arc sine of a */
"atan", atan, 1, /* arc tangent of a */
"atan2", atan2, 2, /* arc tangent of a/b */
"bitand", bitand, 2, /* bitwise AND of int32 versions of a and b */
"bitclear", bitclear,2, /* CLEARs b-th bit of int32 version of a; 0 is lsb */
"bitget", bitget, 2, /* gets b-th bit of int32 version of a; 0 is lsb */
"bitnot", bitnot, 1, /* bitwise NOT of int32 version of a */
"bitor", bitor, 2, /* bitwise OR of int32 versions of a and b */
"bitset", bitset, 2, /* SETs b-th bit of int32 version of a; 0 is lsb */
"bitxor", bitxor, 2, /* bitwise XOR of int32 versions of a and b */
"ceil", ceil, 1, /* smallest integer not less than a */
"cos", cos, 1, /* cosine of a */
"cosh", cosh, 1, /* hyperbolic cosine of a */
"delay", delay, 2, /* a delayed by b iterations */
"delta", delta, 2, /* change in a averaged over b iterations */
"exp", exp, 1, /* exponential of a; i.e. e raised to the a power */
"exp10", Exp10, 1, /* base 10 exponential of a; i.e. 10 raised to the a power */
"fabs", fabs, 1, /* absolute value of a (same as DV_VIABS) */
"floor", floor, 1, /* largest integer value not greater than a */
"fmod", Fmod, 2, /* remainder of a/b */
"gnoise", gnoise, 0, /* gaussian noise, with mean 0, std dev 1 */
"hypot", Hypot, 2, /* sqrt( a*a + b*b ) */
"log", Log, 1, /* the log base e of a */
"log10", Log10, 1, /* the log base 10 of a */
"max", Max, 2, /* the maximum of a and b */
"mean", runmean,2, /* running mean of a over a b-width window */
"min", Min, 2, /* the minimum of a and b */
"pow", Pow, 2, /* a raised to the floor(b) power; a > 0 */
"rsaw", rsaw, 2, /* a=iteration, b=period of reverse saw */
"runmax", runmax, 2, /* running max of a over a b-width window */
"runmean", runmean,2, /* running mean of a over a b-width window */
"runmedian", runmedian,2, /* running median of a over a b-width window (b>0) */
"runmin", runmin, 2, /* running min of a over a b-width window */
"runsdev", runsdev,2, /* running standard deviation of a over a b-width window */
"saw", saw, 2, /* a=iteration, b=period of sawtooth*/
"sin", sin, 1, /* sine of a */
"sinh", sinh, 1, /* hyperbolic sin of a */
"sqrt", sqrt, 1, /* square root of a */
"tan", tan, 1, /* tangent of a */
"tanh", tanh, 1, /* hyperbolic tangent of a */
"time", Time, 0, /* number of seconds since 1 jan 1970 */
"tri", tri, 2, /* a=iteration, b=period of triangle wave */
"wnoise", wnoise, 0, /* white noise in the range [0,1] */
};